const { Readable, Writable } = require('node:stream');
const fs = require('node:fs').promises;
const path = require('node:path');
// const __dirname = path.dirname(__filename);

// 检查文件读权限
async function checkReadPermission(filePath) {
  try {
    /**
     * fs.constants 需要使用 NODE 20 以后的版本。
     */
    await fs.access(filePath, fs.constants.R_OK);
    console.log('文件有读权限');
    return true;
  } catch (err) {
    console.error('文件没有读权限:', err);
    return false;
  }
}

// 检查目录写权限
async function checkWritePermission(dirPath) {
  try {
    await fs.access(dirPath, fs.constants.W_OK);
    console.log('目录有写权限');
    return true;
  } catch (err) {
    console.error('目录没有写权限:', err);
    return false;
  }
}

// 自定义 Readable 流类
class MyReadable extends Readable {
  constructor(filename, options) {
    super(options);
    this.filename = filename;
    this.fd = null;
    this.buffer = Buffer.alloc(1024);
    this.position = 0;
    this.open();
  }

  async open() {
    console.log('Readable打开文件:', this.filename);
    const hasReadPermission = await checkReadPermission(this.filename);
    if (!hasReadPermission) {
      this.emit('error', new Error('文件没有读权限'));
      return;
    }
    fs.open(this.filename, 'r', (err, fd) => {
      console.log('fs.open 回调:', err, fd);
      if (err) {
        this.emit('error', err);
        return;
      }
      this.fd = fd;
      this.emit('open'); // 发射 open 事件
      this.read();
    });
  }

  read() {
    console.log('读取文件:', this.position);
    if (!this.fd) return;
    fs.read(this.fd, this.buffer, 0, this.buffer.length, this.position, (err, bytesRead) => {
      if (err) {
        this.emit('error', err);
        return;
      }
      if (bytesRead === 0) {
        fs.close(this.fd, (err) => {
          if (err) this.emit('error', err);
          this.push(null); // No more data
        });
        return;
      }
      this.position += bytesRead;
      this.push(this.buffer.slice(0, bytesRead));
    });
  }

  _read(size) {
    console.log('_read');
    this.read();
  }
}

// 自定义 Writable 流类
class MyWritable extends Writable {
  constructor(filename, options) {
    super(options);
    this.filename = filename;
    this.fd = null;
    this.open();
  }

  async open() {
    console.log('Writable打开文件:', this.filename);
    const dirPath = path.dirname(this.filename);
    const hasWritePermission = await checkWritePermission(dirPath);
    if (!hasWritePermission) {
      this.emit('error', new Error('目录没有写权限'));
      return;
    }
    fs.open(this.filename, 'w', (err, fd) => {
      console.log('fs.open 回调:', err, fd);
      if (err) {
        this.emit('error', err);
        return;
      }
      this.fd = fd;
      this.emit('open'); // 发射 open 事件
    });
  }

  _write(chunk, encoding, callback) {
    console.log('_write:', chunk, encoding);
    if (!this.fd) {
      this.once('open', () => this._write(chunk, encoding, callback));
      return;
    }
    fs.write(this.fd, chunk, 0, chunk.length, null, (err, bytesWritten) => {
      if (err) {
        this.emit('error', err);
        callback(err);
        return;
      }
      callback();
    });
  }

  _final(callback) {
    if (!this.fd) {
      this.once('open', () => this._final(callback));
      return;
    }
    fs.close(this.fd, (err) => {
      if (err) this.emit('error', err);
      callback(err);
    });
  }
}

// 检查文件和目录权限
(async () => {
  console.log(__dirname)
  const inputFilePath = __dirname + '/input.txt';
  const outputFilePath = __dirname + '/output.txt';

  const hasReadPermission = await checkReadPermission(inputFilePath);
  const hasWritePermission = await checkWritePermission(path.dirname(outputFilePath));

  if (hasReadPermission && hasWritePermission) {
    // 创建自定义的 Readable 和 Writable 流实例
    const myReadable = new MyReadable(inputFilePath);
    const myWritable = new MyWritable(outputFilePath);

    // 将 Readable 流通过管道传递给 Writable 流
    myReadable.pipe(myWritable);

    // 监听错误事件
    myReadable.on('error', (err) => {
      console.error('读取文件时出错:', err);
    });

    myWritable.on('error', (err) => {
      console.error('写入文件时出错:', err);
    });

    myWritable.on('finish', () => {
      console.log('文件传输完成');
    });

    // 添加日志以调试
    myReadable.on('open', () => {
      console.log('Readable 流已打开');
    });

    myWritable.on('open', () => {
      console.log('Writable 流已打开');
    });

    myReadable.on('data', (chunk) => {
      console.log(`Received chunk: ${chunk.length} bytes`);
    });

    myWritable.on('drain', () => {
      console.log('Writable 流已清空');
    });
  }
})();
